from global_names import *

def contour_centre(contour):
	xs = np.array([point[0][0] for point in contour])
	ys = np.array([point[0][1] for point in contour])
	return (np.average(xs),np.average(ys))
def contour_dist(contour1, contour2):
	contour1_centre = contour_centre(contour1)
	contour2_centre = contour_centre(contour2)
	return math.sqrt((contour1_centre[X] - contour2_centre[X])**2+(contour1_centre[Y] - contour2_centre[Y])**2)
def contour_area(contour):
	if contour == None:
		return 0
	else:
		return cv2.contourArea(contour)
def closest_contour(contours, last_contour):
	if last_contour == None:
		return max_contour(contours)
	else:
		min_dist = 999999999
		closest_contour = contours[0]
		closest_idx = 0
		for idx,contour in enumerate(contours):
			dist = contour_dist(contour, last_contour)
			if dist < min_dist:
				closest_contour = contour
				min_dist = dist
				closest_idx = idx
		return (closest_idx,closest_contour)
def max_contour(contours):
	max_contour = None
	max_idx = -1
	for idx,contour in enumerate(contours):
		if contour_area(contour) > contour_area(max_contour):
			max_contour = contour
			max_idx = idx
	return (max_idx,max_contour)
def maxclose_contour(contours, last_contour):
	if last_contour == None:
		return max_contour(contours)
	else:
		last_rect = cv2.boundingRect(last_contour)
		inside_contours = []
		for contour in contours:
			centre = contour_centre(contour)
			if inside_rect(centre, last_rect):
				inside_contours.append(contour)
			else:
				inside_contours.append(None)
		if len(inside_contours) == 0:
			return closest_contour(contours, last_contour)
		else:
			ind, con = max_contour(inside_contours)
			if ind == -1:	return closest_contour(contours, last_contour)
			else:	return (ind, con)
def choose_contour(contours, last_contour, method = 'closestbiggest'):
	if len(contours) == 0:
		return (0,last_contour)
	elif method=='closest': #to previous
		return closest_contour(contours, last_contour)
	elif method=='biggest':
		return max_contour(contours)
	elif method=='closestbiggest': #biggest of those whose centers are within last's bounding box
		return maxclose_contour(contours, last_contour)
def delta_contour(contour1, contour2, method=2): #calculate change between two contours
	if contour1 != None and contour2 != None:
		try:
			delta_area = abs(float(cv2.contourArea(contour2)) - float(cv2.contourArea(contour1)))/float(cv2.contourArea(contour1))
		except ZeroDivisionError:
			delta_area = 1.
		delta_pos = contour_dist(contour1, contour2)
		delta_size = abs(float(len(contour1)) - float(len(contour2)))/float(len(contour1))
		delta_sizearea = delta_size * delta_area
		deltas = (delta_area, delta_pos, delta_size, delta_sizearea)
		return deltas[method]
	else:	return 0
def valid_contours(contours, cell_frames): #determines whether realistic contours
	img = cell_frames[0]
	height,width = (np.size(img, axis=0), np.size(img, axis=1))
	img_area = height * width
	areas = [contour_area(con) for con in contours]
	if np.average(areas) > 0.05*img_area:
		return True
	else:
		return False
	
def inside_rect(point=None, rect=None):
	return point[X] > rect[X] and point[X] < rect[X]+rect[WIDTH] and point[X] > rect[Y] and point[Y] < rect[Y]+rect[HEIGHT]	
def coords_to_rect(coords):
	return [coords[X1],coords[Y1],coords[X2]-coords[X1],coords[Y2]-coords[Y1]] # x y width height
def inside_focus_area(point=None, focus_area=None):
	if type(focus_area[0]) == type(1):
		return inside_rect(point, coords_to_rect(focus_area))
	elif type(focus_area[0]) == type([1]):
		#http://mathforum.org/library/drmath/view/54386.html
		inside_count = 0
		def posneg(line1point,line2point,other_point):
			return other_point[Y] - line1point[Y] - ((line2point[Y] - line1point[Y])/(line2point[X] - line1point[X]))*(other_point[X] - line1point[X])
		#line 1:	
		sign = posneg(focus_area[0],focus_area[1],focus_area[2])
		inside_count += (posneg(focus_area[0],focus_area[1],point) == sign)
		#line 2:	
		sign = posneg(focus_area[1],focus_area[2],focus_area[3])
		inside_count += (posneg(focus_area[1],focus_area[2],point) == sign)
		#line 3:	
		sign = posneg(focus_area[2],focus_area[3],focus_area[0])
		inside_count += (posneg(focus_area[2],focus_area[3],point) == sign)
		#line 4:	
		sign = posneg(focus_area[3],focus_area[0],focus_area[1])
		inside_count += (posneg(focus_area[3],focus_area[0],point) == sign)
		return inside_count == 4
		
"""
def rect_to_coords(rect):
	return [rect[X1],rect[Y1],rect[X1] + rect[WIDTH],rect[Y1] + rect[HEIGHT]] # x1 x2 y1 y2
def rect_size(rect):
	if rect == None:
		return 0
	return float(rect[WIDTH]*rect[HEIGHT])
def inside_coords(rect=None, area=None, contour=None):
	if contour != None:
		rect = cv2.boundingRect(contour)
	return rect[X] > area[X1] and rect[X]+rect[WIDTH] < area[X2] and rect[Y] > area[Y1] and rect[Y]+rect[HEIGHT] < area[Y2]

def rect_centre(rect):
	return (rect[X] + 0.5*rect[WIDTH], rect[Y] + 0.5*rect[HEIGHT])
def rect_dist(rect1, rect2):
	rect1_centre = rect_centre(rect1)
	rect2_centre = rect_centre(rect2)
	return math.sqrt((rect1_centre[X] - rect2_centre[X])**2+(rect1_centre[Y] - rect2_centre[Y])**2)
def max_rect(rects):
	maxrect = [0,0,0,0] #x y width height
	max_idx = -1
	for idx,rect in enumerate(rects):
		if rect_size(rect) > rect_size(maxrect):
			maxrect = rect
			max_idx = idx
	return (max_idx,maxrect)
def closest_rect(rects, last_rec):
	min_dist = 999999999
	closest_rect = rects[0]
	closest_idx = 0
	for idx,rect in enumerate(rects):
		dist = rect_dist(rect, last_rec)
		if dist < min_dist:
			closest_rect = rect
			min_dist = dist
			closest_idx = idx
	return (closest_idx,closest_rect)
def maxclose_rect(rects, last_rect):
	inside_rects = []
	for rect in rects:
		centre = rect_centre(rect)
		if inside_rect(centre, last_rect):
			inside_rects.append(rect)
		else:
			inside_rects.append(None)
	if len(inside_rects) == 0:
		return closest_rect(rects, last_rect)
	else:
		ind, rec = max_rect(inside_rects)
		if ind == -1:	return closest_rect(rects, last_rect)
		else:	return (ind, rec)
def delta_rect(rect1, rect2): #calculate change between two rectangles
	delta_size = abs(rect_size(rect2) - rect_size(rect1))
	delta_pos = rect_dist(rect1, rect2)
	return (delta_pos, delta_size)
def choose_rect(rects=None, last_rect=None, method = 'closest'):
	if method=='closest': #to previous
		return closest_rect(rects, last_rect)
	elif method=='biggest':
		return max_rect(rects)
	elif method=='closestbiggest':
		return maxclose_rect(rects, last_rect)
"""